﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Unscrambler.ViewModels;
using UnscramblerUnitTests.Mocks;

namespace UnscramblerUnitTests.ViewModels
{
    [TestFixture]
    public class GameboardViewModelsTests
    {
        private GameboardViewModel _viewModel;
        private MockGameSettings _mockGameSettings;
        private MockRandomWordChooser _mockWordChooser;
        private bool _gameEndedHandlerCalled;
        

        [SetUp]
        public void Setup()
        {
            _viewModel = new GameboardViewModel();
            _mockGameSettings = new MockGameSettings();
            _mockGameSettings.WordsPerRound = 3;
            _mockGameSettings.SecondsPenaltyPerHint = 60;
            _mockWordChooser = new MockRandomWordChooser();
        }

        [Test]
        public void TestInitialState()
        {
            Assert.IsFalse(_viewModel.IsCurrentWordCorrect);
            Assert.IsFalse(_viewModel.IsGameOver);
            Assert.IsTrue(_viewModel.NumberOfCorrectWords == 0);
            Assert.IsTrue(_viewModel.ElapsedSeconds == 0);
            Assert.IsTrue(_viewModel.CurrentWord == string.Empty);
            Assert.IsTrue(_viewModel.RandomWordChooser == null);
            Assert.IsTrue(_viewModel.NumberOfWords == 0);
            Assert.IsTrue(_viewModel.HintWord == string.Empty);
            Assert.IsTrue(_viewModel.GameSettings == null);
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestStartGameWithoutInjectingGameSettings()
        {
            _viewModel.StartGameCommand.Execute(null);
        }

        [Test]
        public void TestStartGame()
        {
            InjectDependencies();
            Assert.IsTrue(_viewModel.CurrentWord == string.Empty);
            _viewModel.StartGameCommand.Execute(null);
            Assert.IsTrue(_viewModel.CurrentWord == _mockWordChooser.RandomWordToReturn);
            Assert.IsTrue(_viewModel.NumberOfWords == 1);
        }

        private void InjectDependencies()
        {
            _viewModel.GameSettings = _mockGameSettings;
            _viewModel.RandomWordChooser = _mockWordChooser;
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestGetNewWordBeforeStartingGame()
        {
            InjectDependencies();
            _viewModel.NewWordCommand.Execute(null);
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestGetHintdBeforeStartingGame()
        {
            InjectDependencies();
            _viewModel.GetHintCommand.Execute(null);
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestSkipWorddBeforeStartingGame()
        {
            InjectDependencies();
            _viewModel.SkipWordCommand.Execute(null);
        }

        [Test]
        public void TestCanExecuteGetHint()
        {
            Assert.IsFalse(_viewModel.GetHintCommand.CanExecute(null));
            this.TestStartGame();
            Assert.IsTrue(_viewModel.GetHintCommand.CanExecute(null));
        }

        [Test]
        public void TestGetTwoHints()
        {
            this.TestStartGame();
            Assert.IsTrue(_viewModel.HintWord == string.Empty);
            _viewModel.GetHintCommand.Execute(null);
            Assert.IsTrue(_viewModel.HintWord == _mockWordChooser.RandomWordToReturn.Substring(0, 1));
            Assert.IsTrue(_viewModel.ElapsedSeconds >= _mockGameSettings.SecondsPenaltyPerHint);

            _viewModel.GetHintCommand.Execute(null);
            Assert.IsTrue(_viewModel.HintWord == _mockWordChooser.RandomWordToReturn.Substring(0, 2));

        }

        [Test]
        public void TestSkipWord()
        {
            this.TestStartGame();
            Assert.IsTrue(_viewModel.NumberOfWords == 1);
            _viewModel.SkipWordCommand.Execute(null);
            Assert.IsTrue(_viewModel.NumberOfWords == 2);
           
        }

        [Test]
        public void TestGetAnswerCorrect()
        {
            this.TestStartGame();
            Assert.IsFalse(_viewModel.IsCurrentWordCorrect);
            Assert.IsTrue(_viewModel.NumberOfCorrectWords == 0);
            _viewModel.IsCurrentWordCorrect = true;
            _viewModel.NewWordCommand.Execute(null);
            Assert.IsFalse(_viewModel.IsCurrentWordCorrect);
            Assert.IsTrue(_viewModel.NumberOfCorrectWords == 1);
        }

        [Test]
        public void TestGameOver()
        {
            _gameEndedHandlerCalled = false;
            this.TestSkipWord();
            Assert.IsFalse(_viewModel.IsGameOver);
            
            _viewModel.GameEnded += new EventHandler<EventArgs>(_viewModel_GameEnded);
            _viewModel.SkipWordCommand.Execute(null);
            _viewModel.SkipWordCommand.Execute(null);

            Assert.IsTrue(_gameEndedHandlerCalled);
            Assert.IsTrue(_viewModel.IsGameOver);
        }

        void _viewModel_GameEnded(object sender, EventArgs e)
        {
            Assert.IsTrue(sender == _viewModel);
            _gameEndedHandlerCalled = true;
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void TestHintAfterGameOver()
        {
            this.TestGameOver();
            _viewModel.GetHintCommand.Execute(null);
        }

        
      

        
    }
}
